package com.zzy.demo.config.handler;

import java.util.concurrent.TimeUnit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.zzy.cms.core.constant.NumberConst;
import com.zzy.cms.core.dto.CodeMsg;
import com.zzy.cms.core.exception.BizException;
import com.zzy.cms.core.exception.DaoException;
import com.zzy.cms.core.exception.GlobalException;
import com.zzy.cms.core.exception.ParamException;
import com.zzy.cms.core.util.string.IllegalStrFilterUtil;
 
/**
 * 异常处理
 * @author guokaige
 *
 */
@Component
@Aspect
public class AopExceptionHandler {
 
    public static final Logger logger = LoggerFactory.getLogger(AopExceptionHandler.class);
 
    @Pointcut("execution(* com.zzy.demo.web.*.*(..)) "
    		+ "|| execution(* com.zzy.demo.web.*.*.*(..)) "
    		+ "|| execution(* com.zzy.demo.web.*.*.*.*(..))"
    		)
    public void pointCut(){}
    
 
    @Around("pointCut()")
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable{
        Stopwatch stopwatch = Stopwatch.createStarted();
        
        Object result = null;
 
        try {
            logger.info("-----执行Controller开始: " + pjp.getSignature() + " 参数：" + Lists.newArrayList(pjp.getArgs()).toString());
            
            //处理入参特殊字符和sql注入攻击
            checkRequestParam(pjp);
            //执行访问接口操作
            result = pjp.proceed(pjp.getArgs());
            
            Long consumeTime = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
            
            logger.info("-----执行Controller结束: " + pjp.getSignature()+"-----耗时：" + consumeTime + "(毫秒).");
            //当接口请求时间大于5秒时，标记为异常调用时间，并记录入库
            if(consumeTime > NumberConst.NUM_5000){
            	logger.info("-----执行Controller" + pjp.getSignature()+" 耗时大于5秒");
            }
        } catch (Exception throwable) {
            handlerException(pjp, throwable);
        }
		return result;
    }
 
	/**
	 * 处理异常
	 * @param pjp
	 * @param e
	 * @throws Throwable 
	 */
    private void handlerException(ProceedingJoinPoint pjp, Exception e) throws Throwable {
    	e.printStackTrace();
        if (e instanceof DaoException) {
        	logger.error("DaoException{ 方法：{}， 参数：{},异常：{} }", pjp.getSignature(), pjp.getArgs(),e.getMessage());
        	DaoException ex = (DaoException) e;
         	throw new GlobalException(ex.getCodeMsg(),ex);
        } else if (e instanceof BizException) {
        	logger.error("BizException{ 方法：{}， 参数：{},异常：{} }", pjp.getSignature(), pjp.getArgs(),e.getMessage());
        	BizException ex = (BizException) e;
         	throw new GlobalException(ex.getCodeMsg(),ex);
        } else if (e instanceof ParamException) {
            logger.error("ParamException{ 方法：{}， 参数：{},异常：{} }", pjp.getSignature(), pjp.getArgs(),e.getMessage());
            ParamException ex = (ParamException) e;
         	throw new GlobalException(ex.toString(),ex);
        } else if (e instanceof RuntimeException) {
        	logger.error("RuntimeException--- : {}",e);
            logger.error("RuntimeException{ 方法：{}， 参数：{},异常：{} }", pjp.getSignature(), pjp.getArgs(),e.getMessage());
            RuntimeException ex = (RuntimeException) e;
        	throw new GlobalException(null!=e.getMessage()?e.getMessage():CodeMsg.COMMON_SERVER_ERROR.getMsg(),ex);
        } else {
        	logger.error("其他异常--- :{}",e);
            logger.error("其他异常{ 方法：{}， 参数：{},异常：{} }", pjp.getSignature(), pjp.getArgs(),e.getMessage());
        	throw new GlobalException(null!=e.getMessage()?e.getMessage():CodeMsg.COMMON_SERVER_ERROR.getMsg(),e);
        }
 
    }
 

     /**
      * 参数检查
      * @param pjp
      */
    private void checkRequestParam(ProceedingJoinPoint pjp){
        String str = String.valueOf(pjp.getArgs());
        if (!IllegalStrFilterUtil.sqlStrFilter(str)) {
            logger.info("访问接口：" + pjp.getSignature() + "，输入参数存在SQL注入风险！参数为：" + Lists.newArrayList(pjp.getArgs()).toString());
            throw new ParamException(Lists.newArrayList(pjp.getArgs()).toString(),"输入参数存在SQL注入风险！");
        }
        if (!IllegalStrFilterUtil.isIllegalStr(str)) {
            logger.info("访问接口：" + pjp.getSignature() + ",输入参数含有非法字符!，参数为：" + Lists.newArrayList(pjp.getArgs()).toString());
            throw new ParamException(Lists.newArrayList(pjp.getArgs()).toString(),"输入参数含有非法字符!");
        }
    }
 
}
